home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 1.toast / pc / sample code / graphics 3d / opengl drawsprocket / opengl drawsprocket.c next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  20.1 KB  |  633 lines

  1. /*
  2.     File:        OpenGL DrawSprocket.cp
  3.  
  4.     Contains:    An example of OpenGL and DrawSprocket integration for full screen drawing.  
  5.                 Handles multiple displays and timing of swaps per second.
  6.                 
  7.                 The optimal way to select a rendering context would be to check the available devices, find the best,
  8.                 then present the user with a selction dialog only if there are more than one "best" device.
  9.                 Currently there is not a good mechanism to do this easily, so the two best other options are
  10.                 
  11.                 1) iterate throught the available devices find the best renderer, build a DSp context on this,
  12.                 then build your OpenGL context.  The downfall of this method is that you know nothing about the graphics
  13.                 capabilities of the device and the user can't select another screen.  The upside is that you get 
  14.                 a renderer that is has the capabilities you want.
  15.                 
  16.                 2) Allow the user to select a screen to use, build a DSp context and then a OpenGL context.  This
  17.                 second method is simpler but relies on user knowing which device is the best at 3D.
  18.                 
  19.                 This sample illustrates the second method which makes it simpler and allows us to illustrate the
  20.                 DSp/OpenGL interface well.                
  21.  
  22.     Written by:    Geoff Stahl
  23.                 original code by John Stauffer
  24.  
  25.     Copyright:    1999 Apple Computer, Inc., All Rights Reserved
  26.  
  27.     Change History (most recent first):
  28.  
  29.          <6>     11/24/99   GGS        Added better error checking, now all contexts built on window, put gl headers in system path, 
  30.                                      added agl font support, added averaged frame rate, cleaned up code
  31.          <6>     9/14/99    GGS        Corrected buffer rect handling and cleaned up code
  32.          <5>     7/14/99    GGS        Fixed multi-monitor window centering
  33.          <4>     7/13/99    GGS        Add work around for over zealous checking in single buffer DSp context attributes
  34.          <3>     7/5/99     GGS        Now correctly handle multi-monitor (DSp front buffer for single device; Window on top of context for multiple devices)
  35.          <2>     5/28/99    GGS     Added better multi-monitor support, clean code, corrected blanking bug, added timing, correct pixel formats
  36.          <1>        ?        ?      Initial build
  37.  
  38.     This code can be built for DrawSprocket 1.7.  Enable the #define kDSp17 below to add this.
  39.  
  40.       You may incorporate this sample code into your applications without
  41.       restriction, though the sample code has been provided "AS IS" and the
  42.       responsibility for its operation is 100% yours.  However, what you are
  43.       not permitted to do is to redistribute the source as "DSC Sample Code"
  44.       after having made changes. If you're going to re-distribute the source,
  45.      we require that you make it clear in the source that the code was
  46.     descended from Apple Sample Code, but that you've made changes.
  47.     
  48. */
  49.  
  50. // Building with DrawSprocket 1.7
  51. //#define kDSp17 1
  52.  
  53. #include <DrawSprocket.h>
  54. #include <DriverServices.h>
  55. #include <Files.h>
  56. #include <Folders.h>
  57. #include <Fonts.h>
  58. #include <Resources.h>
  59. #include <Sound.h>
  60. #include <TextUtils.h>
  61.  
  62. #include <math.h>
  63. #include <stdio.h>
  64. #include <string.h>
  65.  
  66. #include <agl.h>
  67. #include <aglRenderers.h>
  68. #include <gl.h>
  69.  
  70. //-----------------------------------------------------------------------------------------------------------------------
  71.  
  72. enum 
  73. {
  74.     kBitsPerPixel = 32,
  75.     kContextWidth = 400,
  76.     kContextHeight = 400
  77. };
  78.  
  79. // globals ---------------------------------------------------------------------------------------------------------------
  80.  
  81. const RGBColor    rgbBlack    = { 0x0000, 0x0000, 0x0000 };
  82.  
  83. NumVersion gVersionDSp;
  84. DSpContextAttributes gTheContextAttributes;
  85. DSpContextReference gTheContext;
  86. GLuint gFontList;
  87. char gcstrMode [256] = "";
  88.  
  89.  
  90. // function prototypes ---------------------------------------------------------------------------------------------------
  91.  
  92. void CToPStr (StringPtr outString, const char *inString);
  93. void ReportError (char * strError);
  94. OSStatus DSpDebugStr (OSStatus error);
  95. GLenum aglDebugStr (void);
  96.  
  97. CGrafPtr SetupDSp (GDHandle *hGD, short *numDevices);
  98. void ShutdownDSp (CGrafPtr *ppWin);
  99.  
  100. AGLContext SetupAGL (GDHandle hGD, AGLDrawable win);
  101. void CleanupAGL (AGLContext ctx);
  102. void DrawGL (AGLContext ctx);
  103.  
  104. void DrawFrameRate (GLuint fontList);
  105. void DrawContextInfo (char * cstrContextMode, GLuint fontList);
  106.  
  107. void DrawPSringGL (Str255 pstrOut, GLuint fontList);
  108. void DrawCSringGL (char * cstrOut, GLuint fontList);
  109. GLuint BuildFontGL (AGLContext ctx, GLint fontID, Style face, GLint size);
  110. void DeleteFontGL (GLuint fontList);
  111.  
  112.  
  113. //-----------------------------------------------------------------------------------------------------------------------
  114.  
  115. // main: setup, draw loop, frames per swap timing, clean up (exit with mouse click)
  116.  
  117. int main(void)
  118. {
  119.     CGrafPtr pWin;
  120.     GDHandle hGD;
  121.     short numDevices = 0;
  122.     AGLContext ctx;
  123.     short fNum;
  124.     
  125.     // Mac Init
  126.     MaxApplZone ();
  127.     InitGraf(&qd.thePort);
  128.     InitFonts();
  129.     InitWindows();
  130.     InitMenus();
  131.     TEInit();
  132.     InitDialogs(nil);
  133.     InitCursor();
  134.             
  135.     pWin = SetupDSp (&hGD, &numDevices);                        // Setup DSp for OpenGL
  136.     if (!pWin) 
  137.         return 0;
  138.     ctx = SetupAGL(hGD, (AGLDrawable) pWin);                    // Setup the OpenGL context
  139.     if (!ctx) 
  140.         return 0;
  141.     if (hGD)
  142.         sprintf (gcstrMode, "%d x %d x %d", pWin->portRect.right, pWin->portRect.right, (**(**hGD).gdPMap).pixelSize);
  143.     else
  144.         sprintf (gcstrMode, "%d x %d", pWin->portRect.right, pWin->portRect.right);
  145.     
  146.     GetFNum("\pMonaco", &fNum);                                    // build font
  147.     gFontList = BuildFontGL (ctx, fNum, normal, 9);
  148.  
  149.     do {        
  150.         DrawGL(ctx);                                            // OGL draw
  151.     } while (!Button());
  152.  
  153.     DeleteFontGL (gFontList);
  154.     CleanupAGL(ctx);                                            // Cleanup the OpenGL context
  155.     ShutdownDSp (&pWin);                                        // DSp shutdown
  156.     
  157.     FlushEvents(everyEvent, 0);
  158.     return 0;
  159. }
  160.  
  161. #pragma mark -
  162. //-----------------------------------------------------------------------------------------------------------------------
  163.  
  164. // Copy C string to Pascal string
  165.  
  166. void CToPStr (StringPtr outString, const char *inString)
  167. {    
  168.     unsigned char x = 0;
  169.     do
  170.         *(((char*)outString) + x) = *(inString + x++);
  171.     while ((*(inString + x) != 0)  && (x < 256));
  172.     *((char*)outString) = (char) x;                                    
  173. }
  174.  
  175. // --------------------------------------------------------------------------
  176.  
  177. void ReportError (char * strError)
  178. {
  179.     char errMsgCStr [256];
  180.     Str255 strErr;
  181.  
  182.     sprintf (errMsgCStr, "%s\n", strError); 
  183.  
  184.     // out as debug string
  185.     CToPStr (strErr, errMsgCStr);
  186.     DebugStr (strErr);
  187. }
  188.  
  189. //-----------------------------------------------------------------------------------------------------------------------
  190.  
  191. OSStatus DSpDebugStr (OSStatus error)
  192. {
  193.     switch (error)
  194.     {
  195.         case noErr:
  196.             break;
  197.         case kDSpNotInitializedErr:
  198.             ReportError ("DSp Error: Not initialized");
  199.             break;
  200.         case kDSpSystemSWTooOldErr:
  201.             ReportError ("DSp Error: system Software too old");
  202.             break;
  203.         case kDSpInvalidContextErr:
  204.             ReportError ("DSp Error: Invalid context");
  205.             break;
  206.         case kDSpInvalidAttributesErr:
  207.             ReportError ("DSp Error: Invalid attributes");
  208.             break;
  209.         case kDSpContextAlreadyReservedErr:
  210.             ReportError ("DSp Error: Context already reserved");
  211.             break;
  212.         case kDSpContextNotReservedErr:
  213.             ReportError ("DSp Error: Context not reserved");
  214.             break;
  215.         case kDSpContextNotFoundErr:
  216.             ReportError ("DSp Error: Context not found");
  217.             break;
  218.         case kDSpFrameRateNotReadyErr:
  219.             ReportError ("DSp Error: Frame rate not ready");
  220.             break;
  221.         case kDSpConfirmSwitchWarning:
  222. //            ReportError ("DSp Warning: Must confirm switch"); // removed since it is just a warning, add back for debugging
  223.             return 0; // don't want to fail on this warning
  224.             break;
  225.         case kDSpInternalErr:
  226.             ReportError ("DSp Error: Internal error");
  227.             break;
  228.         case kDSpStereoContextErr:
  229.             ReportError ("DSp Error: Stereo context");
  230.             break;
  231.     }
  232.     return error;
  233. }
  234.  
  235. //-----------------------------------------------------------------------------------------------------------------------
  236.  
  237. // if error dump agl errors to debugger string, return error
  238.  
  239. GLenum aglDebugStr (void)
  240. {
  241.     GLenum err = aglGetError();
  242.     if (AGL_NO_ERROR != err)
  243.         ReportError ((char *)aglErrorString(err));
  244.     return err;
  245. }
  246.  
  247. #pragma mark -
  248. //-----------------------------------------------------------------------------------------------------------------------
  249.  
  250. // Set up DSp screens, handles multi-monitor correctly
  251.  
  252. CGrafPtr SetupDSp (GDHandle *phGD, short *numDevices)
  253. {
  254.     OSStatus err = noErr;
  255.     GDHandle hDevice;
  256.     CGrafPtr pCGOut;
  257.     DSpContextAttributes foundAttributes;
  258.     DisplayIDType displayID;
  259.     Rect rectWin;
  260.     RGBColor rgbSave;
  261.     GrafPtr pGrafSave;
  262.     *numDevices = 0;
  263.  
  264.     // check for DSp
  265.     if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup) 
  266.         ReportError ("DSp not installed");
  267.  
  268.     if (noErr != DSpDebugStr (DSpStartup()))
  269.         return NULL;
  270.  
  271. #ifdef kDSp17
  272.     if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpGetVersion) 
  273. #endif
  274.     {
  275.         // must be 1.1.4 or earlier so look at extension
  276.         short resFileSave, resFileDSp;
  277.         short vRefDSp;
  278.         long dirIDDSp;
  279.         FSSpec fsSpecDSp;
  280.         OSErr err;
  281.         Handle hVersion;
  282.         
  283.         // assume 1.0 version to start with (worst case)
  284.         gVersionDSp.majorRev = 1;
  285.         gVersionDSp.minorAndBugRev = 0;
  286.         gVersionDSp.stage = 0x80;
  287.         gVersionDSp.nonRelRev = 0;
  288.  
  289.         resFileSave = CurResFile();
  290.         SetResLoad (false);
  291.         // search application directory for debug lib
  292.         resFileDSp = OpenResFile ("\pDrawSprocketDebugLib");
  293.         err = ResError ();
  294.         if (fnfErr == err)
  295.         {
  296.             // search application directory for lib
  297.             resFileDSp = OpenResFile ("\pDrawSprocketLib");
  298.             err = ResError ();
  299.             if (fnfErr == err)
  300.             {
  301.                 // search extensions folder for debug lib
  302.                 FindFolder (kOnSystemDisk, kExtensionFolderType, kDontCreateFolder, &vRefDSp, &dirIDDSp);
  303.                 FSMakeFSSpec (vRefDSp, dirIDDSp, "\pDrawSprocketLib", &fsSpecDSp);
  304.                 resFileDSp = FSpOpenResFile (&fsSpecDSp, fsRdPerm);
  305.                 err = ResError ();
  306.                 if (fnfErr == err)
  307.                 {
  308.                     // search extensions folder directory for lib
  309.                     FSMakeFSSpec (vRefDSp, dirIDDSp, "\pDrawSprocketDebugLib", &fsSpecDSp);
  310.                     resFileDSp = FSpOpenResFile (&fsSpecDSp, fsRdPerm);
  311.                     err = ResError ();
  312.                 }
  313.             }
  314.         }
  315.         // if we have an open resource file and no error
  316.         if ((noErr == err) && (-1 != resFileDSp))
  317.         {
  318.             SetResLoad (true);
  319.             hVersion = GetResource ('vers', 1); 
  320.             err = ResError ();
  321.             if ((noErr == err) && (NULL != hVersion))
  322.             {
  323.                 gVersionDSp.majorRev = *(((unsigned char *)*hVersion) + 0);
  324.                 gVersionDSp.minorAndBugRev = *(((unsigned char *)*hVersion) + 1);
  325.                 gVersionDSp.stage = *(((unsigned char *)*hVersion) + 2);
  326.                 gVersionDSp.nonRelRev = *(((unsigned char *)*hVersion) + 3);
  327.                 ReleaseResource (hVersion);
  328.             }
  329.             UseResFile(resFileSave);
  330.             CloseResFile(resFileDSp);
  331.         }    
  332.     }
  333. #ifdef kDSp17
  334.     else
  335.         gVersionDSp = DSpGetVersion ();
  336. #endif
  337.  
  338.     hDevice = DMGetFirstScreenDevice (true);                                // check number of screens
  339.     do
  340.     {
  341.         (*numDevices)++;
  342.         hDevice = DMGetNextScreenDevice (hDevice, true);
  343.     }
  344.     while (hDevice);
  345.             
  346.     // Note: DSp < 1.7.3 REQUIRES the back buffer attributes even if only one buffer is required
  347.     memset(&gTheContextAttributes, 0, sizeof (DSpContextAttributes));
  348.     gTheContextAttributes.displayWidth            = kContextWidth;
  349.     gTheContextAttributes.displayHeight            = kContextHeight;
  350.     gTheContextAttributes.colorNeeds            = kDSpColorNeeds_Require;
  351.     gTheContextAttributes.displayBestDepth        = kBitsPerPixel;
  352.     gTheContextAttributes.backBufferBestDepth    = kBitsPerPixel;
  353.     gTheContextAttributes.displayDepthMask        = kDSpDepthMask_All;
  354.     gTheContextAttributes.backBufferDepthMask    = kDSpDepthMask_All;
  355.     gTheContextAttributes.pageCount                = 1;                                // only the front buffer is needed
  356.     
  357.     // will display user dialog if context selection is required otherwise as find best context
  358.     if (noErr != DSpDebugStr (DSpUserSelectContext(&gTheContextAttributes, 0L, nil, &gTheContext)))
  359.         return NULL;
  360.     if (noErr != DSpDebugStr (DSpContext_GetAttributes (gTheContext, &foundAttributes))) // see what we actually found
  361.         return NULL;
  362.         
  363.     // reset width and height to full screen and handle our own centering
  364.     // HWA will not correctly center less than full screen size contexts
  365.     gTheContextAttributes.displayWidth         = foundAttributes.displayWidth;
  366.     gTheContextAttributes.displayHeight     = foundAttributes.displayHeight;
  367.     gTheContextAttributes.pageCount            = 1;                                    // only the front buffer is needed
  368.     gTheContextAttributes.contextOptions    = 0 | kDSpContextOption_DontSyncVBL;    // no page flipping and no VBL sync needed
  369.  
  370.     DSpSetBlankingColor(&rgbBlack);
  371.     if (noErr !=  DSpDebugStr (DSpContext_GetDisplayID(gTheContext, &displayID)))     // get our device for future use
  372.         return NULL;
  373.     if (noErr !=  DMGetGDeviceByDisplayID(displayID, phGD, false))                     // get GDHandle for ID'd device
  374.     {
  375.         ReportError ("DMGetGDeviceByDisplayID() had an error.");
  376.         return NULL;
  377.     }
  378.     if (noErr !=  DSpDebugStr (DSpContext_Reserve ( gTheContext, &gTheContextAttributes))) // reserve our context
  379.         return NULL;
  380.  
  381.     HideCursor ();
  382.  
  383.     DSpDebugStr (DSpContext_FadeGammaOut (NULL, NULL));                             // fade display, remove for debug
  384.     if (noErr != DSpDebugStr (DSpContext_SetState (gTheContext, kDSpContextState_Active))) // activate our context
  385.         return NULL;
  386.     
  387.     // create a new window in our context 
  388.     // note: OpenGL is expecting a window so it can enumerate the devices it spans, 
  389.     // center window in our context's gdevice
  390.     rectWin.top  = (short) ((***phGD).gdRect.top + ((***phGD).gdRect.bottom - (***phGD).gdRect.top) / 2);          // h center
  391.     rectWin.top  -= (short) (kContextHeight / 2);
  392.     rectWin.left  = (short) ((***phGD).gdRect.left + ((***phGD).gdRect.right - (***phGD).gdRect.left) / 2);    // v center
  393.     rectWin.left  -= (short) (kContextWidth / 2);
  394.     rectWin.right = (short) (rectWin.left + kContextWidth);
  395.     rectWin.bottom = (short) (rectWin.top + kContextHeight);
  396.     
  397.     pCGOut = (CGrafPtr)NewCWindow (NULL, &rectWin, "\p", 0, plainDBox, (WindowPtr)-1, 0, 0);
  398.  
  399.     // paint back ground black before fade in to avoid white background flash
  400.     ShowWindow((GrafPtr)pCGOut);
  401.     GetPort (&pGrafSave);
  402.     SetPort ((GrafPtr)pCGOut);
  403.     GetForeColor (&rgbSave);
  404.     RGBForeColor (&rgbBlack);
  405.     PaintRect (&pCGOut->portRect);
  406.     RGBForeColor (&rgbSave);        // ensure color is reset for proper blitting
  407.     SetPort (pGrafSave);
  408.     
  409.     DSpDebugStr (DSpContext_FadeGammaIn (NULL, NULL));
  410.     
  411.     return pCGOut;
  412. }
  413.  
  414. //-----------------------------------------------------------------------------------------------------------------------
  415.  
  416. // clean up DSp
  417.  
  418. void ShutdownDSp (CGrafPtr *ppWin)
  419. {
  420.     DSpContext_FadeGammaOut (NULL, NULL);
  421.     if (*ppWin)
  422.         DisposeWindow ((WindowPtr)*ppWin);
  423.     *ppWin = NULL;
  424.     DSpContext_SetState( gTheContext, kDSpContextState_Inactive );
  425.     DSpContext_FadeGammaIn (NULL, NULL);
  426.     ShowCursor ();
  427.     DSpContext_Release (gTheContext);
  428.     DSpShutdown ();
  429. }
  430.  
  431. #pragma mark -
  432. //-----------------------------------------------------------------------------------------------------------------------
  433.  
  434. // OpenGL Setup
  435.  
  436. AGLContext SetupAGL (GDHandle hGD, AGLDrawable win)
  437. {
  438. // different possible pixel format choices for different renderers 
  439. // basics requirements are RGBA and double buffer
  440. // OpenGL will select acclerated context if available
  441.  
  442. // software renderer
  443. //    GLint          attrib[] = { AGL_RGBA, AGL_RENDERER_ID, AGL_RENDERER_GENERIC_ID, AGL_ALL_RENDERERS, AGL_DOUBLEBUFFER, AGL_NONE };
  444.  
  445. // any renderer
  446. //    GLint          attrib[] = { AGL_RGBA, AGL_ALL_RENDERERS, AGL_DOUBLEBUFFER, AGL_NONE };
  447.  
  448. // OpenGL compliant HWA renderer 
  449.     GLint          attrib[] = { AGL_RGBA, AGL_ACCELERATED, AGL_DOUBLEBUFFER, AGL_NONE };
  450.  
  451. // OpenGL compliant ATI renderer 
  452. //    GLint          attrib[] = { AGL_RGBA, AGL_RENDERER_ID, AGL_RENDERER_ATI_ID, AGL_DOUBLEBUFFER, AGL_NONE };
  453.  
  454. // OpenGL compliant ATI HWA renderer 
  455. //    GLint          attrib[] = { AGL_RGBA, AGL_RENDERER_ID, AGL_RENDERER_ATI_ID, AGL_ACCELERATED, AGL_DOUBLEBUFFER, AGL_NONE };
  456.  
  457.     AGLPixelFormat     fmt;
  458.     AGLContext         ctx;
  459.  
  460.     if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
  461.     {
  462.         ReportError ("OpenGL not installed\n");
  463.         return NULL;
  464.     }    
  465.  
  466.     if (hGD)
  467.         fmt = aglChoosePixelFormat (&hGD, 1, attrib);             // get an appropriate pixel format
  468.     else
  469.         fmt = aglChoosePixelFormat(NULL, 0, attrib);            // get an appropriate pixel format
  470.     aglDebugStr ();
  471.     if (NULL == fmt) 
  472.     {
  473.         ReportError("Could not find valid pixel format\n");
  474.         return NULL;
  475.     }
  476.     
  477.     ctx = aglCreateContext (fmt, NULL);                            // Create an AGL context
  478.     aglDebugStr ();
  479.     if (NULL == ctx)
  480.     {
  481.         ReportError ("Could not create context\n");
  482.         return NULL;
  483.     }
  484.     
  485.     if (!aglSetDrawable (ctx, win))                                // attach the CGrafPtr to the context
  486.         aglDebugStr ();
  487.     else if (!aglSetCurrentContext (ctx))                        // make the context the current context
  488.     {
  489.         aglDebugStr ();
  490.         aglSetDrawable (ctx, NULL);
  491.     }
  492.  
  493.     aglDestroyPixelFormat(fmt);                                    // pixel format is no longer needed
  494.  
  495.     return ctx;
  496. }
  497.  
  498. //-----------------------------------------------------------------------------------------------------------------------
  499.  
  500. // OpenGL Cleanup
  501.  
  502. void CleanupAGL(AGLContext ctx)
  503. {
  504.     aglSetCurrentContext(NULL);
  505.     aglSetDrawable(ctx, NULL);
  506.     aglDestroyContext(ctx);
  507. }
  508.  
  509. //-----------------------------------------------------------------------------------------------------------------------
  510.  
  511. // OpenGL Drawing
  512.  
  513. void DrawGL(AGLContext ctx)
  514. {
  515.     static float f, s, c;
  516.     GLboolean fState = GL_FALSE;
  517.  
  518.     f += 0.01;
  519.     s = (float) sin(f);
  520.     c = (float) cos(f);
  521.  
  522.     glClearColor(0.15f, 0.15f, 0.15f, 1.0f);                    // Clear color buffer to dark grey
  523.     glClear(GL_COLOR_BUFFER_BIT);
  524.     
  525.     glBegin(GL_POLYGON);                                        // Draw a smooth shaded polygon
  526.     glColor3d(1.0, 0.0, 0.0);
  527.     glVertex3d(s, c, 0.0);
  528.     glColor3d(0.0, 1.0, 0.0);
  529.     glVertex3d(-c, s, 0.0);
  530.     glColor3d(0.0, 0.0, 1.0);
  531.     glVertex3d(-s, -c, 0.0);
  532.     glColor3d(0.7, 0.7, 0.7);
  533.     glVertex3d(c, -s, 0.0);
  534.     glEnd();
  535.     
  536.     // Draw frame rate (set color and position first)
  537.     glColor3d(1.0, 1.0, 1.0);
  538.     glRasterPos3d (-0.95, (kContextHeight - 40.0) / (float) kContextHeight, 0.0); 
  539.     DrawFrameRate (gFontList);
  540.     glRasterPos3d (-0.95, (kContextHeight - 65.0) / (float) kContextHeight, 0.0); 
  541.     DrawContextInfo (gcstrMode, gFontList);
  542.  
  543.     glRasterPos3d (-0.95, -(kContextHeight - 45.0) / (float) kContextHeight, 0.0); 
  544.     DrawCSringGL ((char*) glGetString (GL_VENDOR), gFontList);
  545.     glRasterPos3d (-0.95, -(kContextHeight - 20.0) / (float) kContextHeight, 0.0); 
  546.     DrawCSringGL ((char*) glGetString (GL_RENDERER), gFontList);
  547.  
  548.     aglSwapBuffers(ctx);
  549. }
  550.  
  551. #pragma mark -
  552. //-----------------------------------------------------------------------------------------------------------------------
  553.  
  554. // Draw frame rate in curent color at current raster positon with provided font display list
  555.  
  556. void DrawFrameRate (GLuint fontList)
  557. {    
  558.     static char aChar[256] = "";
  559.     static AbsoluteTime time = {0,0};
  560.     static long frames = 0;
  561.  
  562.     AbsoluteTime currTime = UpTime ();
  563.     float deltaTime = (float) AbsoluteDeltaToDuration (currTime, time);
  564.     
  565.     frames++;
  566.  
  567.     if (0 > deltaTime)    // if negative microseconds
  568.         deltaTime /= -1000000.0;
  569.     else                // else milliseconds
  570.         deltaTime /= 1000.0;
  571.     if (0.5 <= deltaTime)    // has update interval passed
  572.     {
  573.         sprintf (aChar, "Swaps/Sec: %0.1f", frames / deltaTime);
  574.         time = currTime;    // reset for next time interval
  575.         frames = 0;
  576.     }
  577.     
  578.     DrawCSringGL (aChar, fontList);
  579. }
  580.  
  581. //-----------------------------------------------------------------------------------------------------------------------
  582.  
  583. // Draw height,width, bit pixel and frequency for context
  584.  
  585. void DrawContextInfo (char * cstrContextMode, GLuint fontList)
  586. {    
  587.     DrawCSringGL (cstrContextMode, fontList);
  588. }
  589.  
  590. #pragma mark -
  591. //-----------------------------------------------------------------------------------------------------------------------
  592.  
  593. void DrawPSringGL (Str255 pstrOut, GLuint fontList)
  594. {
  595.     GLint i;
  596.     for (i = 1; i <= pstrOut[0]; i++)
  597.         glCallList (fontList + pstrOut[i]);
  598. }
  599.  
  600. //-----------------------------------------------------------------------------------------------------------------------
  601.  
  602. void DrawCSringGL (char * cstrOut, GLuint fontList)
  603. {
  604.     GLint i = 0;
  605.     while (cstrOut [i])
  606.         glCallList (fontList + cstrOut[i++]);
  607. }
  608.  
  609. //-----------------------------------------------------------------------------------------------------------------------
  610.  
  611. GLuint BuildFontGL (AGLContext ctx, GLint fontID, Style face, GLint size)
  612. {
  613.     GLuint listBase = glGenLists (256);
  614.     if (aglUseFont (ctx, fontID , face, size, 0, 256, (long) listBase))
  615.     {
  616.         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  617.         return listBase;
  618.     }
  619.     else
  620.     {
  621.         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  622.         glDeleteLists (listBase, 256);
  623.         return 0;
  624.     }
  625. }
  626.  
  627. //-----------------------------------------------------------------------------------------------------------------------
  628.  
  629. void DeleteFontGL (GLuint fontList)
  630. {
  631.     if (fontList)
  632.         glDeleteLists (fontList, 256);
  633. }